package com.nervenets.web.service;

import com.alibaba.fastjson.JSON;
import com.icbc.api.DefaultIcbcClient;
import com.icbc.api.IcbcApiException;
import com.icbc.api.request.*;
import com.icbc.api.response.*;
import com.icbc.util.*;
import com.nervenets.Global;
import com.nervenets.utils.JodaUtils;
import com.nervenets.utils.StringUtils;
import com.nervenets.web.hibernate.domain.AccountHold;
import com.nervenets.web.hibernate.domain.AccountOpen;
import com.nervenets.web.hibernate.domain.AccountOpenBinding;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.zip.Deflater;

@Component
@Slf4j
public class IcbcService implements InitializingBean {
    public static String APP_ID = Global.getApplicationProperties().getProperty("app.id");
    public static String MY_PRIVATE_KEY = Global.getApplicationProperties().getProperty("my.private.key");
    public static String APIGW_PUBLIC_KEY = Global.getApplicationProperties().getProperty("apigw.public.key");
    public static String MY_SM2_PRIVATE_KEY = Global.getApplicationProperties().getProperty("my.sm2.private.key");
    public static String ICBC_SM2_PUBLIC_KEY = Global.getApplicationProperties().getProperty("icbc.sm2.public.key");
    public static String MY_API_DOMAIN = Global.getApplicationProperties().getProperty("app.base.domain");

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {
        APP_ID = environment.getProperty("app.id");
        MY_PRIVATE_KEY = environment.getProperty("my.private.key");
        APIGW_PUBLIC_KEY = environment.getProperty("apigw.public.key");
        MY_SM2_PRIVATE_KEY = environment.getProperty("my.sm2.private.key");
        ICBC_SM2_PUBLIC_KEY = environment.getProperty("icbc.sm2.public.key");
        MY_API_DOMAIN = environment.getProperty("app.base.domain");
    }


    /**
     * 上传开户影像
     *
     * @param open
     * @param binding
     * @throws Exception
     */
    public SettlementAccountOpenRealtimeimgUploadResponseV1 settlementAccountOpenRealtimeImageUpload(AccountOpen open, AccountOpenBinding binding) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key();  //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, "RSA2", MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountOpenRealtimeimgUploadRequestV1 request =
                new SettlementAccountOpenRealtimeimgUploadRequestV1();
        SettlementAccountOpenRealtimeimgUploadRequestV1.SettlementAccountOpenRealtimeimgUploadRequestV1Biz bizContent =
                new SettlementAccountOpenRealtimeimgUploadRequestV1.SettlementAccountOpenRealtimeimgUploadRequestV1Biz();
        request.setServiceUrl(environment.getProperty("icbc.url") + environment.getProperty("icbc.SettlementAccountOpenRealtimeImageUploadV1"));
        bizContent.setOutServiceCode("uploadimg");
        bizContent.setCorpNo(APP_ID);                    //合作方机构编号
        bizContent.setCorpSerno(binding.getCorpSernoOriginal());                //合作方交易单号
        bizContent.setTrxDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方交易日期
        bizContent.setTrxTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCertNo(SecretUtils.encryptSM4(sm4Key, open.getIdCard()));  //SM4加密的证件号码  使用ECB会报324异常
        bizContent.setCustName(SecretUtils.encryptSM4(sm4Key, open.getTrueName()));//SM4加密的客户姓名
        if (open.getIdCardInvalidDate().equals("forever")) {
            bizContent.setValidityPeriod("9999-12-30");
        } else {
            bizContent.setValidityPeriod(open.getIdCardInvalidDate());//证件失效期
        }
        bizContent.setFrontImgType("01");
        bizContent.setBackImgType("01");
        bizContent.setFrontImg(encodeImgageToBase64(open.getIdFrontImage()));//正面
        bizContent.setBackImg(encodeImgageToBase64(open.getIdBackImage()));//背面
        bizContent.setClearFlag(0);
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //使用SM2加密的SM4对称密钥
        request.setBizContent(bizContent);
        log.info("ICBC: {}", JSON.toJSONString(request));
        SettlementAccountOpenRealtimeimgUploadResponseV1 response = client.execute(request);
        log.info("ICBC: {}", JSON.toJSONString(response));

        if (response.isSuccess() && response.getReturnCode() == 0) {
            //SaveFileUtils.setSmsSendNo(response.getSmsSendNo());//保存短信验证码编号
        } else {
        }
        return response;
    }


    public String encodeImgageToBase64(String imageUrl) throws Exception {// 将图片文件转化为字节数组字符串，并对其进行DEFLATE压缩+Base64编码处理
        try {
            //通过ticket换取二维码
            URL url = new URL(imageUrl);
            // 打开连接
            URLConnection con = url.openConnection();
            // 输入流
            InputStream is = con.getInputStream();
            // 1K的数据缓冲
            byte[] bs = new byte[1024];
            // 读取到的数据长度
            int len;
            // 输出的文件流
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            // 开始读取
            while ((len = is.read(bs)) != -1) {
                os.write(bs, 0, len);
            }
            // 完毕，关闭所有链接
            os.close();
            is.close();


            byte[] b = deflateCompress(os.toByteArray());
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(b);
        } catch (Exception e) {
            //
        }
        return null;
    }


    //进行DEFLATE压缩
    public byte[] deflateCompress(byte[] input) throws Exception {
        //String charset = "UTF-8";
        //byte[] input = str.getBytes(charset);
        log.info("ICBC: {}", "[deflateCompress]:input length:" + input.length);
        byte[] output = new byte[1024 * 1024];//input.length + 10 + new Double(Math.ceil(input.length*0.25f)).intValue()
        log.info("ICBC: {}", "[deflateCompress]output length:" + output.length);
        Deflater deflater = new Deflater();
        deflater.setInput(input);
        deflater.finish();
        int compressesDateLength = deflater.deflate(output);
        deflater.end();
        log.info("ICBC: {}", "ByteString after deflate is:" + Arrays.copyOf(output, compressesDateLength));
        return Arrays.copyOf(output, compressesDateLength);
    }


    /**
     * 开户
     *
     * @param open
     * @param binding
     * @return
     * @throws Exception
     */
    public SettlementAccountOpenResponseV2 settlementAccountOpenV2(AccountOpen open, AccountOpenBinding binding) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key();  //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, "RSA2", MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountOpenRequestV2 request = new SettlementAccountOpenRequestV2();
        SettlementAccountOpenRequestV2.SettlementAccountOpenRequestV2Biz bizContent = new SettlementAccountOpenRequestV2.SettlementAccountOpenRequestV2Biz();
        request.setServiceUrl(environment.getProperty("icbc.url") + environment.getProperty("icbc.SettlementAccountOpenV1")); //API地址
        bizContent.setBindMedium(SecretUtils.encryptSM4(sm4Key, binding.getBindCard()));//sm4加密的一类户卡号
        bizContent.setBindMediumHash(MD5Util.string2MD5(binding.getBindCard())); //绑定的I类卡的HASH值
        bizContent.setCertNo(SecretUtils.encryptSM4(sm4Key, open.getIdCard()));  //SM4加密的证件号码  使用ECB会报324异常
        bizContent.setCertType(0); //证件类型
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setCorpMediumId(open.getIdCard());//合作方介质号，不能重复，介质不同对应可以开辟多个II类账户
        bizContent.setCorpNo(APP_ID);//合作方机构编号
        bizContent.setCorpSerno(binding.getCorpSerNo()); //合作方交易单号，保存单号，短信验证/订单查询时使用
        bizContent.setCustName(SecretUtils.encryptSM4(sm4Key, open.getTrueName()));//SM4加密的客户姓名
        if ("forever".equals(open.getIdCardInvalidDate())) {
            bizContent.setForeverFlag(1);
        } else {
            bizContent.setForeverFlag(0);
            bizContent.setValidityPeriod(open.getIdCardInvalidDate());//证件失效期
        }
        bizContent.setImgUploadStatus(1);
        bizContent.setGender(1);
        bizContent.setMobileNo(SecretUtils.encryptSM4(sm4Key, binding.getMobile()));//SM4加密的手机号码
        bizContent.setNationality(156);
        bizContent.setNotifyAddr(String.format("https://%s/api/v1/bank/openNotify", MY_API_DOMAIN));
        bizContent.setOccupation(2);//职业
        bizContent.setOutServiceCode("openaccount"); //外部服务代码
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //使用SM2加密的SM4对称密钥
        bizContent.setSignDate(open.getIdCardSignDate()); //证件签发日期
        bizContent.setTaxDeclarationFlag(0);
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间

        bizContent.setAccountOrgNo(open.getAccountOrgNo());
        bizContent.setImgUploadStatus(1);

        request.setBizContent(bizContent);
        log.info("ICBC: {}", JSON.toJSONString(request));
        SettlementAccountOpenResponseV2 response = client.execute(request);
        log.info("ICBC: {}", JSON.toJSONString(response));
        if (response.isSuccess() && response.getReturnCode() == 0) {
            log.info("ICBC: {}", binding.getCorpSerNo());
        } else {
        }
        return response;
    }

    /**
     * 验证码验证
     *
     * @param binding 订单号
     * @throws IcbcApiException
     */
    public SettlementAccountSCodeVerifyResponseV1 settlementAccountSCodeVerifyV1(AccountOpenBinding binding, String smsCode) throws IcbcApiException {
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, "RSA2", MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountSCodeVerifyRequestV1 request = new SettlementAccountSCodeVerifyRequestV1();
        SettlementAccountSCodeVerifyRequestV1.SettlementAccountSCodeVerifyRequestV1Biz bizContent = new SettlementAccountSCodeVerifyRequestV1.SettlementAccountSCodeVerifyRequestV1Biz();
        request.setServiceUrl(environment.getProperty("icbc.url") + environment.getProperty("icbc.SettlementAccountSCodeVerifyV1"));//API地址
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方工作日期
        bizContent.setCorpNo(APP_ID);//合作方机构编号
        String corpSerno = Util.getNonceStr(16);
        bizContent.setCorpSerno(corpSerno);//合作方交易单号
        bizContent.setCorpSernoOriginal(binding.getCorpSerNo());//原合作方交易单号 绑定
        bizContent.setOutServiceCode("scodeverify");//外部服务代码
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setSmsSCode(smsCode);//短信验证码 测试3环境默认为955888
        bizContent.setSmsSendNo(binding.getSmsSendNo());//短信验证码编号，上一个测试方法执行回来的
        request.setBizContent(bizContent);
        log.info("ICBC: {}", JSON.toJSONString(request));
        SettlementAccountSCodeVerifyResponseV1 response = client.execute(request);
        log.info("ICBC: {}", JSON.toJSONString(response));
        if (response.isSuccess() && response.getReturnCode() == 0) {
            //成功
            log.info("ICBC: {}", "II类卡号：" + SecretUtils.decryptMediumId(response.getMediumId(), response.getSecretKey(), MY_SM2_PRIVATE_KEY));
        } else {
            //失败
        }
        return response;
    }

    /**
     * 验证码重发
     *
     * @param binding
     * @throws IcbcApiException
     */
    public SettlementAccountSCodeSendResponseV1 settlementAccountSCodeSendV1(AccountOpenBinding binding) throws IcbcApiException {
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, "RSA2", MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountSCodeSendRequestV1 request = new SettlementAccountSCodeSendRequestV1();
        SettlementAccountSCodeSendRequestV1.SettlementAccountSCodeRequestV1Biz bizContent = new SettlementAccountSCodeSendRequestV1.SettlementAccountSCodeRequestV1Biz();
        request.setServiceUrl(environment.getProperty("icbc.url") + environment.getProperty("icbc.SettlementAccountSCodeSendV1"));//API地址
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方工作日期
        bizContent.setCorpNo(APP_ID);//合作方机构编号，我行分配的机构编号
        bizContent.setCorpSerno(binding.getCorpSerNo());//合作方交易单号
        bizContent.setCorpSernoOriginal(binding.getCorpSerNo());//原合作方交易单号 绑定
        bizContent.setOutServiceCode("scode"); //外部服务代码
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        request.setBizContent(bizContent);
        log.info("ICBC: {}", JSON.toJSONString(request));
        SettlementAccountSCodeSendResponseV1 response = client.execute(request);
        log.info("ICBC: {}", JSON.toJSONString(response));
//        if (response.isSuccess() && response.getReturnCode() == 0) {
//            //成功
//            log.info("ICBC: {}",response.getSmsSendNo());
//        } else {
//            //失败
//        }
        return response;
    }

    /**
     * 查询开户进度
     *
     * @param binding
     * @return
     * @throws IcbcApiException
     */
    public SettlementAccountOpenQueryResponseV1 settlementAccountOpenQueryV1(AccountOpenBinding binding) throws IcbcApiException {
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountOpenQueryRequestV1 request = new SettlementAccountOpenQueryRequestV1();
        SettlementAccountOpenQueryRequestV1.SettlementAccountOpenQueryRequestV1Biz bizContent = new SettlementAccountOpenQueryRequestV1.SettlementAccountOpenQueryRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountOpenQueryV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setOutServiceCode("queryopenbook"); //外部服务代码
        bizContent.setOpenCorpSerno(binding.getCorpSerNo());//原合作方交易单号  绑定
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountOpenQueryResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
//        if (response.isSuccess() && response.getReturnCode() == 0) {
//            //成功
//            System.out.println("II类卡号：" + SecretUtils.decryptMediumId(response.getMediumId(), response.getSecretKey(), MY_SM2_PRIVATE_KEY));
//        } else {
//            //失败
//        }
        return response;
    }

    /**
     * 查询开户成功后二三类卡的信息
     */
    public SettlementAccountInfoQueryResponseV1 settlementAccountInfoQueryV1(AccountOpen open) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key(); //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountInfoQueryRequestV1 request = new SettlementAccountInfoQueryRequestV1();
        SettlementAccountInfoQueryRequestV1.SettlementAccountInfoQueryRequestV1Biz bizContent = new SettlementAccountInfoQueryRequestV1.SettlementAccountInfoQueryRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountInfoQueryV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("queryinfo");
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2()));//工行联名卡号
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY));//密钥
        request.setBizContent(bizContent);
        SettlementAccountInfoQueryResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess()) {
            final String custName = SecretUtils.decryptMediumId(response.getCustName(), response.getSecretKey(), MY_SM2_PRIVATE_KEY);
            System.out.println("用户名：" + custName);
            final String certNo = SecretUtils.decryptMediumId(response.getCertNo(), response.getSecretKey(), MY_SM2_PRIVATE_KEY);
            System.out.println("证件号：" + certNo);
            response.setCustName(custName);
            response.setCertNo(certNo);
        } else {
        }
        return response;
    }

    /**
     * 余额查询
     *
     * @param open
     * @return
     * @throws Exception
     */
    public SettlementAccountBalanceQueryResponseV1 settlementAccountBalanceQueryV1(AccountOpen open) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key(); //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountBalanceQueryRequestV1 request = new SettlementAccountBalanceQueryRequestV1();
        SettlementAccountBalanceQueryRequestV1.SettlementAccountBalanceQueryRequestV1Biz bizContent = new SettlementAccountBalanceQueryRequestV1.SettlementAccountBalanceQueryRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountBalanceQueryV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("querybalance"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setCcy(1); //币种
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY));//SM4密钥
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountBalanceQueryResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess() && response.getReturnCode() == 0) {
            System.out.println("可用余额：" + response.getAccountBalance()); // 可用余额
            System.out.println("保留金额：" + response.getHoldBalance()); // 保留金额
        }
        return response;
    }


    /**
     * 交易明细
     *
     * @param open
     * @param queryMode
     * @param page
     * @param pnBusidate
     * @param pnRowRecord
     * @return
     * @throws Exception
     */
    public SettlementAccountDetailQueryResponseV1 settlementAccountDetailQueryV1(AccountOpen open, int queryMode, int page, String pnBusidate, String pnRowRecord) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key(); //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountDetailQueryRequestV1 request = new SettlementAccountDetailQueryRequestV1();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountDetailQueryV1"));//API地址
        SettlementAccountDetailQueryRequestV1.SettlementAccountDetailQueryRequestV1Biz bizContent = new SettlementAccountDetailQueryRequestV1.SettlementAccountDetailQueryRequestV1Biz();
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("querydetail"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setCcy(1); //币种
        bizContent.setBeginDate(JodaUtils.timeLongToString(open.getCreateTime() * 1000L, "yyyy-MM-dd")); //开始日期
        bizContent.setEndDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //结束日期
        bizContent.setQueryMode(queryMode); //查询方式1-首次查询2-上一页3-下一页
        bizContent.setPage(page); //页码（首次查询送1，下一页加1，上一页减1）
        bizContent.setPnBusidate(pnBusidate); //上次入账日期（翻页时必输，查询上页送上页查询结果第一条记录的入账日期，查询下页送最近一次查询结果最后一条记录的入账日期）
        bizContent.setPnRowRecord(pnRowRecord); //翻页条件记录（翻页时必输，查询上页送上页查询结果第一条记录的翻页条件，查询下页送最近一次查询结果最后一条记录的翻页条件）
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY));//密钥
        bizContent.setMediumIdHash(MD5Util.string2MD5(open.getCard2()));//联名卡的hash值
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountDetailQueryResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess() && response.getReturnCode() == 0) {
            // 业务成功处理
            if (null != response.getOrderDetail() && !response.getOrderDetail().isEmpty()) {
                response.getOrderDetail().forEach(orderDetailInfo -> {
                    if (!StringUtils.isEmpty(orderDetailInfo.getMediumId())) {
                        final String mediumId = SecretUtils.decryptMediumId(orderDetailInfo.getMediumId(), response.getSecretKey(), MY_SM2_PRIVATE_KEY);
                        orderDetailInfo.setMediumId(mediumId);
                    }
                    if (!StringUtils.isEmpty(orderDetailInfo.getCpMediumId())) {
                        final String cpMediumId = SecretUtils.decryptMediumId(orderDetailInfo.getCpMediumId(), response.getSecretKey(), MY_SM2_PRIVATE_KEY);
                        orderDetailInfo.setCpMediumId(cpMediumId);
                    }
                    if (!StringUtils.isEmpty(orderDetailInfo.getResavName())) {
                        final String resavName = SecretUtils.decryptMediumId(orderDetailInfo.getResavName(), response.getSecretKey(), MY_SM2_PRIVATE_KEY);
                        orderDetailInfo.setResavName(resavName);
                    }
                });
            }
        } else {
            // 失败
        }
        return response;
    }

    /**
     * 资金冻结
     *
     * @param open
     * @param money
     * @param buildId
     * @return
     * @throws Exception
     */
    public SettlementAccountHoldResponseV1 settlementAccountHoldV1(AccountOpen open, int money, long buildId) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key();//生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountHoldRequestV1 request = new SettlementAccountHoldRequestV1();
        SettlementAccountHoldRequestV1.SettlementAccountHoldRequestV1Biz bizContent = new SettlementAccountHoldRequestV1.SettlementAccountHoldRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountHoldV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("accounthold"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setCcy(1); //币种
        bizContent.setCashExFlag(9); //钞汇标志
        bizContent.setAmount(String.valueOf(money)); //交易金额
        bizContent.setHoldType(57);  //保留种类
        bizContent.setSummary("DY"); //摘要
        bizContent.setRemarks(String.valueOf(buildId)); //注释buildId
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //sm4对称密钥
        bizContent.setMediumIdHash(MD5Util.string2MD5(open.getCard2())); //卡号哈希值
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountHoldResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess() && response.getReturnCode() == 0) {
            // 业务成功处理
            System.out.println("实际余额：" + response.getAccountBalance());
            System.out.println("可用余额：" + response.getAccountUseamt());
        } else {
            // 失败
        }
        return response;
    }

    /**
     * 资金解冻
     *
     * @param open
     * @param hold
     */
    public SettlementAccountUnholdResponseV1 settlementAccountUnholdV1(AccountOpen open, AccountHold hold) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key();//生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountUnholdRequestV1 request = new SettlementAccountUnholdRequestV1();
        SettlementAccountUnholdRequestV1.SettlementAccountUnholdRequestV1Biz bizContent = new SettlementAccountUnholdRequestV1.SettlementAccountUnholdRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountUnholdV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("accountunhold"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setCcy(1); //币种
        bizContent.setCashExFlag(9); //钞汇标志
        bizContent.setAmount(String.valueOf(hold.getMoney())); //交易额300元 与单笔保留的金额一致

        bizContent.setHoldType(57); //保留种类
        bizContent.setHoldDate(JodaUtils.timeLongToString(hold.getCreateTime() * 1000L, "yyyy-MM-dd"));//原认筹保留日期 保留时，返回的数据
        bizContent.setSummary("资金解除保留"); //摘要
        bizContent.setRemarks(String.valueOf(hold.getBuildingId())); //注释  需要和保留时的字段一致buildId
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY));//SM4密钥
        bizContent.setMediumIdHash(MD5Util.string2MD5(open.getCard2()));//卡号的哈希值
        request.setBizContent(bizContent);
        SettlementAccountUnholdResponseV1 response = client.execute(request);
        System.out.println(com.icbc.api.internal.util.internal.util.fastjson.JSON.toJSONString(response));
        if (response.isSuccess() && response.getReturnCode() == 0) {
            // 业务成功处理
            System.out.println("实际余额：" + response.getAccountBalance());
            System.out.println("可用余额：" + response.getAccountUseamt());
        } else {
            // 失败
        }
        return response;
    }

    /**
     * 查询绑定的一类账号
     *
     * @param open
     * @return
     * @throws Exception
     */
    public SettlementAccountBindingQueryResponseV1 settlementAccountBindingQueryV1(AccountOpen open) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key(); //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountBindingQueryRequestV1 request = new SettlementAccountBindingQueryRequestV1();
        SettlementAccountBindingQueryRequestV1.SettlementAccountBindingQueryRequestV1Biz bizContent = new SettlementAccountBindingQueryRequestV1.SettlementAccountBindingQueryRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountBindingQueryV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("querybinding"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //sm4对称密钥
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountBindingQueryResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
//        if (response.isSuccess()) {
//            for (String detail : response.getRecordDetail()) {
//                final JSONObject object = JSON.parseObject(detail);
//                final String bindMedium = object.getString("bind_medium");
//                System.out.println("绑定卡号：" + SecretUtils.decryptMediumId(bindMedium, response.getSecretKey(), MY_SM2_PRIVATE_KEY));
//            }
//        } else {
//        }
        return response;
    }

    /**
     * 绑定新的一类卡
     *
     * @param open
     * @param binding
     * @return
     * @throws Exception
     */
    public SettlementAccountBindingResponseV1 settlementAccountBindingV1(AccountOpen open, AccountOpenBinding binding) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key(); //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountBindingRequestV1 request = new SettlementAccountBindingRequestV1();
        SettlementAccountBindingRequestV1.SettlementAccountBindingRequestV1Biz bizContent = new SettlementAccountBindingRequestV1.SettlementAccountBindingRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountBindingV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("binding"); //外部服务代码
        bizContent.setCorpMediumId(open.getIdCard()); //合作方介质号
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setBindMedium(SecretUtils.encryptSM4(sm4Key, binding.getBindCard())); //绑定的I类卡号
        bizContent.setCertType(0); //证件类型
        bizContent.setCertNo(SecretUtils.encryptSM4(sm4Key, open.getIdCard())); //证件号码
        bizContent.setCustName(SecretUtils.encryptSM4(sm4Key, open.getTrueName())); //户名
        bizContent.setMobileNo(SecretUtils.encryptSM4(sm4Key, binding.getMobile())); //手机号
        bizContent.setNotifyAddr(String.format("https://%s/api/v1/bank/bindingNotify", MY_API_DOMAIN)); //通知地址
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //使用SM2加密的SM4对称密钥
        bizContent.setBindMediumHash(MD5Util.string2MD5(open.getCard2())); //绑定的I类卡的HASH值
        bizContent.setMediumIdHash(MD5Util.string2MD5(binding.getBindCard())); //联名卡卡号哈希值
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountBindingResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess()) {
            //SaveFileUtils.setSmsSendNo(response.getSmsSendNo());//保存短信验证码编号
        } else {
        }
        return response;
    }

    /**
     * 解绑一类卡
     *
     * @param open
     * @param binding
     * @return
     * @throws Exception
     */
    public SettlementAccountUnbindingResponseV1 settlementAccountUnbindingV1(AccountOpen open, AccountOpenBinding binding) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key(); //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountUnbindingRequestV1 request = new SettlementAccountUnbindingRequestV1();
        SettlementAccountUnbindingRequestV1.SettlementAccountUnbindingRequestV1Biz bizContent = new SettlementAccountUnbindingRequestV1.SettlementAccountUnbindingRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountUnbindingV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("unbinding"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setBindMedium(SecretUtils.encryptSM4(sm4Key, binding.getBindCard())); //绑定的I类卡号
        bizContent.setMobileNo(SecretUtils.encryptSM4(sm4Key, binding.getBindCard())); //手机号
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //sm4对称密钥
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountUnbindingResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        return response;
    }

    /**
     * 转账
     *
     * @param open
     * @param outBankNumber
     * @param inBankNumber
     * @param money
     * @return
     * @throws Exception
     */
    @Deprecated
    public SettlementAccountOrientedTransferResponseV1 settlementAccountOrientedTransferV1(AccountOpen open, String outBankNumber, String inBankNumber, int money) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key();//生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountOrientedTransferRequestV1 request = new SettlementAccountOrientedTransferRequestV1();
        SettlementAccountOrientedTransferRequestV1.SettlementAccountOrientedTransferRequestV1Biz bizContent = new SettlementAccountOrientedTransferRequestV1.SettlementAccountOrientedTransferRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountOrientedTransferV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("orientedtransfer"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, inBankNumber)); //我行卡号
        bizContent.setCcy(1); //币种
        bizContent.setCashExFlag(0); //钞汇标志
        bizContent.setAmount(String.valueOf(money)); //交易金额
        bizContent.setOaccno(SecretUtils.encryptSM4(sm4Key, outBankNumber));//对手账户
        bizContent.setDrcrdirection(1);//借贷方向
        bizContent.setSummary("诚意金转账"); //摘要
        bizContent.setRemarks("诚意金转账"); //注释
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY));//加密密钥
        bizContent.setCertNo(SecretUtils.encryptSM4(sm4Key, open.getIdCard()));//证件号码
        bizContent.setCertType(0);//证件类型
        bizContent.setCustName(SecretUtils.encryptSM4(sm4Key, open.getTrueName()));//用户名
        request.setBizContent(bizContent);

        System.out.println(JSON.toJSONString(request));
        SettlementAccountOrientedTransferResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess()) {
            //成功
        } else {
        }
        return response;
    }

    /**
     * 充值
     *
     * @param open
     * @param accountNumber1
     * @param money
     * @return
     * @throws Exception
     */
    public SettlementAccountRechargeResponseV1 settlementAccountRechargeV1(AccountOpen open, String accountNumber1, int money) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key();//生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountRechargeRequestV1 request = new SettlementAccountRechargeRequestV1();
        SettlementAccountRechargeRequestV1.SettlementAccountRechargeRequestV1Biz bizContent = new SettlementAccountRechargeRequestV1.SettlementAccountRechargeRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountRechargeV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss")); //合作方交易时间
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setOutServiceCode("recharge"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setBindMedium(SecretUtils.encryptSM4(sm4Key, accountNumber1)); //绑定的I类卡号
        bizContent.setCcy(1); //币种
        bizContent.setCashExFlag(0); //钞汇标志
        bizContent.setAmount(String.valueOf(money)); //交易金额 300元
        bizContent.setSummary("DY"); //摘要
        bizContent.setRemarks("DY"); //注释
        bizContent.setNotifyAddr(String.format("https://%s/api/v1/bank/rechargeNotify", MY_API_DOMAIN)); //通知地址
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //sm4对称密钥
        bizContent.setMediumIdHash(MD5Util.string2MD5(open.getCard2())); //卡号哈希值
        bizContent.setBindMediumHash(MD5Util.string2MD5(accountNumber1)); //绑定介质哈希值
        bizContent.setCorrectionFlag(0);//冲账标志
        // bizContent.setCorrectionDate("2019-04-02");//冲账日期 必须正确,否则会报错
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountRechargeResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess() && response.getReturnCode() == 0) {
            //成功
        } else {
            //失败
        }
        return response;
    }

    /**
     * 提现
     *
     * @param open
     * @param accountNumber1
     * @param money
     * @return
     * @throws Exception
     */
    public SettlementAccountWithdrawResponseV1 settlementAccountWithdrawV1(AccountOpen open, String accountNumber1, int money) throws Exception {
        String sm4Key = GenerateKeyUtils.generateSM4Key(); //生成SM4密钥
        DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
        SettlementAccountWithdrawRequestV1 request = new SettlementAccountWithdrawRequestV1();
        SettlementAccountWithdrawRequestV1.SettlementAccountWithdrawRequestV1Biz bizContent = new SettlementAccountWithdrawRequestV1.SettlementAccountWithdrawRequestV1Biz();
        request.setServiceUrl(Global.getApplicationProperties().getProperty("icbc.url") + Global.getApplicationProperties().getProperty("icbc.SettlementAccountWithdrawV1"));//API地址
        bizContent.setCorpNo(APP_ID); //合作方机构编号
        bizContent.setTrxAccDate(JodaUtils.timeLongToString("yyyy-MM-dd"));//合作方交易日期
        bizContent.setTrxAccTime(JodaUtils.timeLongToString("HH:mm:ss"));//合作方交易时间
        bizContent.setCorpSerno(StringUtils.randomString(16)); //合作方交易单号
        bizContent.setCorpDate(JodaUtils.timeLongToString("yyyy-MM-dd")); //合作方工作日期
        bizContent.setOutServiceCode("withdraw"); //外部服务代码
        bizContent.setMediumId(SecretUtils.encryptSM4(sm4Key, open.getCard2())); //工行联名卡号
        bizContent.setBindMedium(SecretUtils.encryptSM4(sm4Key, accountNumber1)); //绑定的I类卡号
        bizContent.setCcy(1); //币种
        bizContent.setCashExFlag(0); //钞汇标志
        bizContent.setAmount(String.valueOf(money)); //交易金额
        bizContent.setSummary("DY"); //摘要
        bizContent.setRemarks("DY"); //注释
        bizContent.setNotifyAddr(String.format("https://%s/api/v1/bank/withdrawNotify", MY_API_DOMAIN)); //通知地址
        bizContent.setSecretKey(SecretUtils.encryptSM2(sm4Key, ICBC_SM2_PUBLIC_KEY)); //sm4对称密钥
        bizContent.setMediumIdHash(MD5Util.string2MD5(open.getCard2())); //卡号哈希值
        bizContent.setBindMediumHash(MD5Util.string2MD5(accountNumber1)); //绑定介质哈希值
        bizContent.setCorrectionFlag(0);//冲账标志
        // bizContent.setCorrectionDate("2017-03-14");//冲账日期
        request.setBizContent(bizContent);
        System.out.println(JSON.toJSONString(request));
        SettlementAccountWithdrawResponseV1 response = client.execute(request);
        System.out.println(JSON.toJSONString(response));
        if (response.isSuccess()) {
            //成功
        } else {
            //失败
        }
        return response;
    }
}
